package com.example.servicegateway.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

/**
 * 全局认证过滤器
 * 
 * 功能说明：
 * 1. 对所有经过网关的请求进行统一的认证检查
 * 2. 验证请求头中的认证信息（如Token）
 * 3. 对白名单路径进行放行处理
 * 4. 记录请求日志和认证结果
 * 
 * @author Spring Cloud Demo
 * @version 1.0
 * @since 2024-01-01
 */
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(GlobalAuthFilter.class);

    /**
     * 白名单路径列表，这些路径不需要认证
     */
    private static final List<String> WHITE_LIST = Arrays.asList(
            "/api/health",           // 健康检查
            "/api/actuator/**",      // 监控端点
            "/api/public/**",        // 公开接口
            "/api/auth/login",       // 登录接口
            "/api/auth/register"     // 注册接口
    );

    /**
     * 认证Token的请求头名称
     */
    private static final String AUTH_TOKEN_HEADER = "Authorization";

    /**
     * 过滤器执行方法
     * 
     * @param exchange 服务器Web交换对象，包含请求和响应信息
     * @param chain 过滤器链，用于继续执行下一个过滤器
     * @return Mono<Void> 异步处理结果
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        
        // 获取请求路径
        String path = request.getPath().value();
        
        // 记录请求日志
        logger.info("🔍 网关收到请求: {} {}", request.getMethod(), path);
        
        // 检查是否为白名单路径
        if (isWhiteListPath(path)) {
            logger.info("✅ 白名单路径，跳过认证: {}", path);
            return chain.filter(exchange);
        }
        
        // 获取认证Token
        String token = getAuthToken(request);
        
        // 验证Token
        if (!StringUtils.hasText(token)) {
            logger.warn("❌ 请求缺少认证Token: {}", path);
            return unauthorized(exchange, "缺少认证Token");
        }
        
        // 验证Token有效性（这里简化处理，实际项目中应该调用认证服务）
        if (!isValidToken(token)) {
            logger.warn("❌ Token无效: {}", token);
            return unauthorized(exchange, "Token无效");
        }
        
        // 认证通过，继续执行过滤器链
        logger.info("✅ 认证通过，继续处理请求: {}", path);
        
        // 在请求头中添加用户信息（可选）
        ServerHttpRequest modifiedRequest = request.mutate()
                .header("X-User-Id", getUserIdFromToken(token))
                .build();
        
        // 使用修改后的请求继续处理
        return chain.filter(exchange.mutate().request(modifiedRequest).build());
    }

    /**
     * 获取过滤器执行顺序，数字越小优先级越高
     * 
     * @return 执行顺序
     */
    @Override
    public int getOrder() {
        return -100; // 设置为高优先级，确保在其他过滤器之前执行
    }

    /**
     * 检查是否为白名单路径
     * 
     * @param path 请求路径
     * @return true表示是白名单路径，false表示需要认证
     */
    private boolean isWhiteListPath(String path) {
        return WHITE_LIST.stream().anyMatch(whitePath -> {
            if (whitePath.endsWith("/**")) {
                // 处理通配符路径
                String prefix = whitePath.substring(0, whitePath.length() - 2);
                return path.startsWith(prefix);
            }
            return path.equals(whitePath);
        });
    }

    /**
     * 从请求头中获取认证Token
     * 
     * @param request 请求对象
     * @return 认证Token，如果不存在则返回null
     */
    private String getAuthToken(ServerHttpRequest request) {
        String authHeader = request.getHeaders().getFirst(AUTH_TOKEN_HEADER);
        if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7); // 去除"Bearer "前缀
        }
        return null;
    }

    /**
     * 验证Token有效性
     * 
     * @param token 认证Token
     * @return true表示Token有效，false表示Token无效
     */
    private boolean isValidToken(String token) {
        // 这里简化处理，实际项目中应该：
        // 1. 调用认证服务验证Token
        // 2. 检查Token是否过期
        // 3. 验证Token签名等
        
        // 示例：简单的Token格式验证
        return token != null && token.length() > 10;
    }

    /**
     * 从Token中提取用户ID
     * 
     * @param token 认证Token
     * @return 用户ID
     */
    private String getUserIdFromToken(String token) {
        // 这里简化处理，实际项目中应该解析JWT Token
        // 示例：返回一个固定的用户ID
        return "user-123";
    }

    /**
     * 返回未授权响应
     * 
     * @param exchange 服务器Web交换对象
     * @param message 错误消息
     * @return Mono<Void> 异步处理结果
     */
    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }
} 